#ifndef __GLOBALS_H__
#define __GLOBALS_H__

#include "unp.h"
#include "unpifiplus.h"
#include "unprtt.h"
#include <setjmp.h>

#define log_msg_msg(msg1, msg2) printf("[debug print]>>[%s(%d)] %s: %s\n" , __FILE__,\
        __LINE__, msg1, msg2)

#define log_msg(message) printf("[debug print]>>[%s(%d)] %s\n" , __FILE__,\
        __LINE__, message)

#define log_msg_int(message, val) printf("[debug print]>>[%s(%d)] %s:%d\n" ,\
        __FILE__, __LINE__, message, val)

#define log_msg_int_int(message, val1, val2) printf("[debug print]>>[%s(%d)] %s:%d %d\n",\
        __FILE__, __LINE__, message, val1, val2)

#define TRUE 1
#define FALSE 0

#define TMP_BUFSIZE 100
#define MAX_DATAGRAM_SZ 512
#define MAX_DATAGRAM_BUF_SIZE (MAX_DATAGRAM_SZ - (3*sizeof(int)) -\
        sizeof(uint32_t))

#define SRV_LOG "\n[SERVER_LOG]"
#define CLI_LOG "\n[CLIENT_LOG]"

#define QFLAG_Q 1
#define QFLAG_DONTQ 0


#define max(a,b) a>b?a:b

/**
TODO: Description
  */
struct sock_ele
{
	int sockfd;
	char ip_addr[INET_ADDRSTRLEN+5];
	char net_mask[INET_ADDRSTRLEN];
	char sub_mask[INET_ADDRSTRLEN];
};

typedef struct
{
    uint32_t tstamp;
    int seq_num;
    int ack_num;
    int wsize;
    char data[MAX_DATAGRAM_BUF_SIZE];
}datagram;

typedef struct 
{
    datagram* dgram;
    struct datagram_list* link;
}datagram_list;

typedef struct
{
    int win_r;
    int win_l;
    int win_size;
}arq_params;

void parse_server_in(int *server_port, int *win);
void sig_chld(int);
void get_subnet_mask(char ip_addr[], char net_mask[], char sub_mask[]);
void parse_client_in(char ip_server[], int * server_port, char filename[], int*\
        Win, int * seed, float * p, int * mu);
int set_interface_info(struct sock_ele s[], int server_port);
int  do_select(
    int ele_count,
    struct sock_ele s[],
    fd_set * rset,
    char filename[],
    char ip_client[],
    int client_port,
    char ip_server[],
    int *i
    );
int 
get_route_flags(
        char ip_server[],
        char ip_client[],
        char sub_mask[]
        );

int 
encode_data(
        char data_bufr[],
        int len,
        datagram* dgram
        );
void 
decode_data(
        datagram,
        char buf[]
        );

datagram *
prep_datagram(
        char dgram_bufr[]
        );

ssize_t
send_datagram(
        int sockfd,
        char* buf,
        int flags,
        datagram_list* head,
        int qflag
        );
void
Sendto_datagram(
        int sockfd,
        char* buf,
        int flags,
        struct sockaddr* src_addr,
        socklen_t addrlen,
        datagram_list* head,
        int qflag
        );

void
recvfrom_datagram(
        int sockfd,
        char* buf,
        int flags,
        struct sockaddr* src_addr,
        socklen_t* addrlen,
        int *rcwin
        );
void
recv_datagram(
        int sockfd,
        char* buf,
        int flags
        );

void 
append_buffer(
        datagram_list* head,
        datagram* dgram
        );
void
traverse_datagram_buffer(
        datagram_list head
        );
void 
remove_from_buffer(
        int seqno,
        datagram_list* head
        );

datagram_list* 
find_datagram(
        datagram_list* head,
        int num
        );

void 
print_ack_array(
        int arr[],
        int size
        );
int 
done_receiving_acks(
        int arr[],
        int size
        );

int 
calc_slide(
        int arr[],
        int size
        );

void
reset_ack_flags(
        int arr[],
        int size
        );

void
send_window(
        int fd,
        int flags,
        arq_params* win,
        datagram_list* head,
        int ack_array[],
        int slide_val
        );
int 
fill_window(
        arq_params* win,
        datagram_list* head,
        int fd,
        int * eof_reached
        );
int 
slide(
        arq_params* win,
        int ack_array[]
     );

int 
should_slide(
        int arr[],
        int size
        );

int 
stop_sending(
        int eof_reached,
        int ack_num,
        int win_r
        );

void 
server_to_client ( 
        FILE * fp, 
        int confd, 
        datagram* dg_ptr, 
        int flags, 
        datagram_list * packet_buffer_head,
        int rcwin,
        int serv_win
        );

#endif
 
